#include "LineManager.h"
#include "VertexManager.h"

CLineManager::CLineManager(CVertexManager* pVManager)
{
	m_lSegment.clear();
	m_lScaffold.clear();
	m_pVManager = pVManager;
}

CLineManager::~CLineManager()
{
	m_pVManager = NULL;
}

bool CLineManager::AddLineSegment(CLineSegment l)
{
	CLineSegmentIter it;
	for (it = m_lSegment.begin(); it != m_lSegment.end(); it++)
		if (*it == l)
			return false;
	CVertex lStart = *l.m_start;
	CVertex lEnd = *l.m_end;
	CVertexIter vertIt;
	for (vertIt = m_pVManager->m_lVertex.begin(); vertIt != m_pVManager->m_lVertex.end(); vertIt++)
	{
		if (IsInLineSegment(vertIt->m_v3D, l))
		{
			CLineSegment line;
			line.m_start = l.m_start;
			line.m_end = &(*vertIt);
			AddLineSegment(line);
			line.m_start = &(*vertIt);
			line.m_end = l.m_end;
			AddLineSegment(line);
			return true;
		}
	}
	if (vertIt == m_pVManager->m_lVertex.end())
		m_lSegment.push_front(l);
	
	//	test for intersection
	CVertex start, end, v;
	CScaffoldIter scaIt;
	SKE_LINEINTERSECT_SOLUTION type;
	for (scaIt = m_lScaffold.begin(); scaIt != m_lScaffold.end(); scaIt++)
	{
		start = *scaIt->m_start;
		end = *scaIt->m_end;
		v.m_v3D = ComputeIntersection(lStart.m_v3D, start.m_v3D, 
			lEnd.m_v3D - lStart.m_v3D, end.m_v3D - start.m_v3D, type);
		if (type == ONE_SOL && v.m_v3D != start.m_v3D && v.m_v3D != end.m_v3D 
			&& IsInLineSegment(v.m_v3D, l))
		{
			v.m_v2D = ComputeIntersection(lStart.m_v2D, start.m_v2D, 
				lEnd.m_v2D - lStart.m_v2D, end.m_v2D - start.m_v2D, type);
			m_pVManager->AddVertex(v);
		}
	}
	CLineSegmentIter lineIt;
	for (lineIt = m_lSegment.begin(); lineIt != m_lSegment.end(); lineIt++)
	{
		start = *lineIt->m_start;
		end = *lineIt->m_end;
		v.m_v3D = ComputeIntersection(lStart.m_v3D, start.m_v3D, 
			lEnd.m_v3D - lStart.m_v3D, end.m_v3D - start.m_v3D, type);
		if (type == ONE_SOL && (IsInLineSegment(v.m_v3D, *lineIt) && IsInLineSegment(v.m_v3D, l)))
		{
			v.m_v2D = ComputeIntersection(lStart.m_v2D, start.m_v2D, 
				lEnd.m_v2D - lStart.m_v2D, end.m_v2D - start.m_v2D, type);
			m_pVManager->AddVertex(v);
		}
	}
	return true;
}

void CLineManager::AddLineFromHead(CLineSegment l)
{
	m_lSegment.push_front(l);
}

bool CLineManager::DeleteLineFromHead()
{
	if (m_lSegment.size() == 0)
		return false;
	m_lSegment.pop_front();
	return true;
}

bool CLineManager::AddScaffold(CScaffold s)
{
	CScaffoldIter it;
	for (it = m_lScaffold.begin(); it != m_lScaffold.end(); it++)
	{
		if (IsInScaffold(it->m_start->m_v3D, s) && IsInScaffold(it->m_end->m_v3D, s))
			return false;
	}
	m_lScaffold.push_front(s);
	//	add new vertices
	CLineSegmentIter lineIt;
	CVertex v, lStart, lEnd;
	SKE_LINEINTERSECT_SOLUTION type;
	for (lineIt = m_lSegment.begin(); lineIt != m_lSegment.end(); lineIt++)
	{
		lStart = *lineIt->m_start;
		lEnd = *lineIt->m_end;
		v.m_v3D = ComputeIntersection(lStart.m_v3D, s.m_start->m_v3D,
			lEnd.m_v3D - lStart.m_v3D, s.m_end->m_v3D - s.m_start->m_v3D, type);
		if (type == ONE_SOL && IsInLineSegment(v.m_v3D, *lineIt))
		{
			v.m_v2D = ComputeIntersection(lStart.m_v2D, s.m_start->m_v2D,
				lEnd.m_v2D - lStart.m_v2D, s.m_end->m_v2D - s.m_start->m_v2D, type);
			m_pVManager->AddVertex(v);
		}
	}
	CScaffoldIter scaIt;
	for (scaIt = m_lScaffold.begin(); scaIt != m_lScaffold.end(); scaIt++)
	{
		lStart = *scaIt->m_start;
		lEnd = *scaIt->m_end;
		v.m_v3D = ComputeIntersection(lStart.m_v3D, s.m_start->m_v3D,
			lEnd.m_v3D - lStart.m_v3D, s.m_end->m_v3D - s.m_start->m_v3D, type);
		if (type == ONE_SOL)
		{
			v.m_v2D = ComputeIntersection(lStart.m_v2D, s.m_start->m_v2D,
				lEnd.m_v2D - lStart.m_v2D, s.m_end->m_v2D - s.m_start->m_v2D, type);
			m_pVManager->AddVertex(v);
		}
	}
	return true;
}

bool CLineManager::DeleteLineSegment(CLineSegment l)
{
	return true;
}

bool CLineManager::DeleteScaffold(CScaffold s)
{
	return true;
}

int CLineManager::GetLineSegmentCount()
{
	return m_lSegment.size();
}

int CLineManager::GetScaffoldCount()
{
	return m_lScaffold.size();
}

CLineSegment CLineManager::GetLineSegment(int index)
{
	int count = GetLineSegmentCount();
	index = (index >= 0) ? index : 0;
	index = (index < count) ? index : count - 1;
	CLineSegmentIter it;
	int temp = 0;
	for (it = m_lSegment.begin(); it != m_lSegment.end(); it++, temp++)
	{
		if (temp == index)
			return *it;
	}
	CLineSegment l;
	l.m_start = NULL;
	l.m_end = NULL;
	return l;
}

CScaffold CLineManager::GetScaffold(int index)
{
	int count = GetScaffoldCount();
	index = (index >= 0) ? index : 0;
	index = (index < count) ? index : count - 1;
	CScaffoldIter it;
	int temp = 0;
	for (it = m_lScaffold.begin(); it != m_lScaffold.end(); it++, temp++)
	{
		if (temp == index)
			return *it;
	}
	CScaffold s;
	s.m_start = NULL;
	s.m_end = NULL;
	return s;
}

CLineSegment CLineManager::GetNearestLineSegment(CVertex v, CVector2D dir)
{
	int lineCount = m_lSegment.size();
	CLineSegment line, minLine;
	CVector2D curDir;
	float curAngle, minAngle = M_PI;
	minLine.m_start = minLine.m_end = NULL;
	for (int i = 0; i < lineCount; i++)
	{
		line = GetLineSegment(i);
		curDir = line.m_end->m_v2D - line.m_start->m_v2D;
		curAngle = CalcAngle(dir, curDir);
		if (curAngle > M_PI / 2) curAngle = M_PI - curAngle;
		if (IsInLineSegment(v.m_v3D, line) && curAngle < minAngle)
		{
			minAngle = curAngle;
			minLine = line;
		}
	}
	return minLine;
}

CScaffold CLineManager::GetNearestScaffold(CVertex v, CVector2D dir)
{
	int scaffoldCount = m_lScaffold.size();
	CScaffold scaffold, minScaffold;
	CVector2D curDir;
	float curAngle, minAngle = M_PI;
	minScaffold.m_start = minScaffold.m_end = NULL;
	for (int i = 0; i < scaffoldCount; i++)
	{
		scaffold = GetScaffold(i);
		curDir = scaffold.m_end->m_v2D - scaffold.m_start->m_v2D;
		curAngle = CalcAngle(dir, curDir);
		if (curAngle > M_PI / 2) curAngle = M_PI - curAngle;
		if (IsInScaffold(v.m_v3D, scaffold) && curAngle < minAngle)
		{
			minAngle = curAngle;
			minScaffold = scaffold;
		}
	}
	return minScaffold;
}